﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography;
using ICSharpCode.SharpZipLib.Zip;

namespace MCSharpLib.MCrytion
{
    public class DASCryption
    {

        private string publicKey = "", privateKey = "";
        private RSACryptoServiceProvider crypt;
        public DASCryption()
        {
            crypt = new RSACryptoServiceProvider();
        }


        /// <summary>
        /// DAS 设置秘钥
        /// </summary>
        /// <param name="category">秘钥种类:0-公钥,1-私钥</param>
        /// <param name="key">秘钥字符</param>
        public void SetKey(int category, string key)
        {
            if (category == 0)
            {
                publicKey = key;
            }
            else
            {
                privateKey = key;
            }
        }

        /// <summary>
        /// DAS 生成秘钥
        /// </summary>
        /// <param name="filepath">秘钥存放的位置</param>
        public void ExtKeys(string filepath = "")
        {
            string pbKey = crypt.ToXmlString(false);
            string prKey = crypt.ToXmlString(true);
            StreamWriter one = new StreamWriter(filepath + "publicKey.Key", true, UTF8Encoding.UTF8);
            one.Write(pbKey);
            StreamWriter two = new StreamWriter(filepath + "privateKey.Key", true, UTF8Encoding.UTF8);
            two.Write(prKey);
            one.Flush();
            two.Flush();
            one.Close();
            two.Close();
        }

        /// <summary>
        /// DAS 加密二进制文件
        /// </summary>
        /// <param name="fileSource">需要加密的文件</param>
        /// <param name="fileDest">加密后文件存放的位置</param>
        public void DeCryptByteFile(string fileSource, string fileDest)
        {
            crypt.FromXmlString(privateKey);
            FileStream fs = new FileStream(fileSource, FileMode.Open);
            FileStream writopic = new FileStream(fileDest, FileMode.Create);
            byte[] bytes = new byte[fs.Length];
            fs.Read(bytes, 0, (int)fs.Length);
            fs.Close();
            MemoryStream ms = new MemoryStream();
            int keySize = crypt.KeySize / 8;
            byte[] rawblock, decryptblock;
            for (int i = 0; i < bytes.Length; i += keySize)
            {
                if ((bytes.Length - i) > keySize)
                {
                    rawblock = new byte[keySize];
                }
                else
                { rawblock = new byte[bytes.Length - i]; }
                Buffer.BlockCopy(bytes, i, rawblock, 0, rawblock.Length);
                decryptblock = crypt.Decrypt(rawblock, false);
                ms.Write(decryptblock, 0, decryptblock.Length);
            }
            ms.Position = 0;
            byte[] decode = new byte[ms.Length];
            ms.Read(decode, 0, (int)ms.Length);
            ms.Close();
            writopic.Write(decode, 0, decode.Length);
            writopic.Close();
        }

        /// <summary>
        /// DAS 解密文件
        /// </summary>
        /// <param name="fileSource">需要解密的文件</param>
        /// <param name="fileDest">解密后文件存放的位置</param>
        public void EnCryptByteFile(string fileSource, string fileDest)
        {
            crypt.FromXmlString(publicKey);
            FileStream picfs = new FileStream(fileSource, FileMode.Open);
            FileStream fs = new FileStream(fileDest, FileMode.OpenOrCreate);
            byte[] bytes = new byte[picfs.Length];
            picfs.Read(bytes, 0, (int)picfs.Length);
            picfs.Close();
            int blockSize = 0;
            if (crypt.KeySize == 1024)
                blockSize = 16;
            else blockSize = 8;
            byte[] rawblock, encryblock;
            for (int i = 0; i < bytes.Length; i += blockSize)
            {
                if ((bytes.Length - i) > blockSize)
                    rawblock = new byte[blockSize];
                else rawblock = new byte[bytes.Length - i];
                Buffer.BlockCopy(bytes, i, rawblock, 0, rawblock.Length);
                encryblock = crypt.Encrypt(rawblock, false);
                fs.Write(encryblock, 0, encryblock.Length);
            }
            fs.Flush();
            fs.Close();
        }

        /// <summary>
        /// DAS 加密文本
        /// </summary>
        /// <param name="pToDeCrypt">需要解密的文本</param>
        /// <returns>解密后的文本</returns>
        public string DeCryptText(string pToDeCrypt)
        {
            crypt.FromXmlString(privateKey);
            UTF8Encoding enc = new UTF8Encoding();
            byte[] inputByteArray = new byte[pToDeCrypt.Length / 2];
            for (int x = 0; x < pToDeCrypt.Length / 2; x++)
            {
                int i = (Convert.ToInt32(pToDeCrypt.Substring(x * 2, 2), 16));
                inputByteArray[x] = (byte)i;
            }
            MemoryStream ms = new MemoryStream();
            int blockSize = crypt.KeySize / 8;
            byte[] rawblock, decryptblock;
            for (int i = 0; i < inputByteArray.Length; i += blockSize)
            {
                if ((inputByteArray.Length - i) > blockSize)
                {
                    rawblock = new byte[blockSize];
                }
                else
                { rawblock = new byte[inputByteArray.Length - i]; }
                Buffer.BlockCopy(inputByteArray, i, rawblock, 0, rawblock.Length);
                decryptblock = crypt.Decrypt(rawblock, false);
                ms.Write(decryptblock, 0, decryptblock.Length);
            }
            ms.Position = 0;
            byte[] decode = new byte[ms.Length];
            ms.Read(decode, 0, (int)ms.Length);
            string text = enc.GetString(decode);
            return text;
        }

        /// <summary>
        /// DAS 加密文本
        /// </summary>
        /// <param name="pToEnCrypt">需要加密文本</param>
        /// <returns>加密后的文本</returns>
        public string EnCryptText(string pToEnCrypt)
        {
            crypt.FromXmlString(publicKey);
            UTF8Encoding enc = new UTF8Encoding();
            byte[] bytes = enc.GetBytes(pToEnCrypt);
            int blockSize = 0;
            if (crypt.KeySize == 1024)
                blockSize = 16;
            else
                blockSize = 8;
            MemoryStream ms = new MemoryStream();
            byte[] rawblock, encryblock;
            for (int i = 0; i < bytes.Length; i += blockSize)
            {
                if ((bytes.Length - i) > blockSize)
                    rawblock = new byte[blockSize];
                else
                    rawblock = new byte[bytes.Length - i];
                Buffer.BlockCopy(bytes, i, rawblock, 0, rawblock.Length);
                encryblock = crypt.Encrypt(rawblock, false);
                ms.Write(encryblock, 0, encryblock.Length);
            }
            ms.Position = 0;
            byte[] decode = new byte[ms.Length];
            ms.Read(decode, 0, (int)ms.Length);

            StringBuilder ret = new StringBuilder();
            foreach (byte b in decode)
            {
                ret.AppendFormat("{0:X2}", b);
            }
            ret.ToString();
            return ret.ToString();
        }
    }

    public class DESCryption
    {
        private DESCryptoServiceProvider crypt;

        public DESCryption()
        {
            crypt =  new DESCryptoServiceProvider();
        }

        /// <summary>
        /// DEC 设置秘钥
        /// </summary>
        /// <param name="sKey">秘钥字符串最大8位</param>
        public void SetKey(string sKey)
        {
            //建立加密对象的密钥和偏移量
            crypt.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
            //原文使用ASCIIEncoding.ASCII方法的GetBytes方法
            crypt.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
        }

        /// <summary>
        /// DEC 加密字符
        /// </summary>
        /// <param name="pToEncrypt">被加密的字符串</param>
        /// <returns>返回被加密的字符串</returns>
        public string EncryptText(string pToEncrypt)
        {
            byte[] inputByteArray = Encoding.Default.GetBytes(pToEncrypt);//把字符串放到byte数组中

            MemoryStream ms = new MemoryStream();//创建其支持存储区为内存的流　
            //定义将数据流链接到加密转换的流
            CryptoStream cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write);
            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();
            //上面已经完成了把加密后的结果放到内存中去

            StringBuilder ret = new StringBuilder();
            foreach (byte b in ms.ToArray())
            {
                ret.AppendFormat("{0:X2}", b);
            }
            ret.ToString();
            return ret.ToString();
        }

        /**/
        /// <summary>
        /// DEC 解密字符
        /// </summary>
        /// <param name="pToDecrypt">被解密的字符串</param>
        /// <returns>返回被解密的字符串</returns>
        public string DeCryptText(string pToDecrypt)
        {

            byte[] inputByteArray = new byte[pToDecrypt.Length / 2];
            for (int x = 0; x < pToDecrypt.Length / 2; x++)
            {
                int i = (Convert.ToInt32(pToDecrypt.Substring(x * 2, 2), 16));
                inputByteArray[x] = (byte)i;
            }

            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, crypt.CreateDecryptor(), CryptoStreamMode.Write);

            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();

            //建立StringBuild对象，createDecrypt使用的是流对象，必须把解密后的文本变成流对象
            StringBuilder ret = new StringBuilder();

            return System.Text.Encoding.Default.GetString(ms.ToArray());
        }

        /// <summary>
        /// DEC解密二进制文件
        /// </summary>
        /// <param name="fileSource">需要解密的文件</param>
        /// <param name="fileDest">解密后的文件</param>
        public void DeCryptByteFile(string fileSource, string fileDest)
        {
            FileStream fs = new FileStream(fileSource, FileMode.Open);
            FileStream writopic = new FileStream(fileDest, FileMode.Create);
            byte[] bytes = new byte[fs.Length];
            fs.Read(bytes, 0, (int)fs.Length);
            fs.Close();
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, crypt.CreateDecryptor(), CryptoStreamMode.Write);
            cs.Write(bytes, 0, bytes.Length);
            cs.FlushFinalBlock();
            ms.Position = 0;
            byte[] decode = new byte[ms.Length];
            ms.Read(decode, 0, (int)ms.Length);
            ms.Close();
            writopic.Write(decode, 0, decode.Length);
            writopic.Close();
        }

        /// <summary>
        /// DEC加密二进制文件
        /// </summary>
        /// <param name="fileSource">需要加密的文件</param>
        /// <param name="fileDest">加密后的文件</param>
        public void EnCryptByteFile(string fileSource, string fileDest)
        {
            FileStream fs = new FileStream(fileSource, FileMode.Open);
            FileStream writopic = new FileStream(fileDest, FileMode.Create);
            byte[] bytes = new byte[fs.Length];
            fs.Read(bytes, 0, (int)fs.Length);
            fs.Close();
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write);
            cs.Write(bytes, 0, bytes.Length);
            cs.FlushFinalBlock();
            ms.Position = 0;
            byte[] decode = new byte[ms.Length];
            ms.Read(decode, 0, (int)ms.Length);
            ms.Close();
            writopic.Write(decode, 0, decode.Length);
            writopic.Close();
        }
    }

    public class Base64Code
    {
        /// <summary>
        /// Base64编码
        /// </summary>
        /// <param name="source">原始文本</param>
        /// <returns>编码后的文本</returns>
        public static string EncodeBase64(string source)
        {
            try
            {
                byte[] bytes_1 = System.Text.Encoding.Default.GetBytes(source);
                return Convert.ToBase64String(bytes_1);
            }
            catch
            {
                return "";
            }
        }

        /// <summary>
        /// Base64解码
        /// </summary>
        /// <param name="result">编码后的文本</param>
        /// <returns>原始文本</returns>
        public static string DecodeBase64(string result)
        {
            try
            {
                byte[] bytes_2 = Convert.FromBase64String(result);
                return System.Text.Encoding.Default.GetString(bytes_2);
            }
            catch
            {
                return result;
            }
        }
    }
    public class Zip
    {
        /// <summary>
        /// 解压文件
        /// </summary>
        /// <param name="file">压缩文件</param>
        /// <param name="destFolder">解压目录</param>
        public void UnZipFile(string file, string destFolder)   //解压缩
        {
            int i2 = 0;  //防止名称冲突的参数
            if (!Directory.Exists(destFolder))
                Directory.CreateDirectory(destFolder);     //创建以解压时间为名称的文件夹
            ZipInputStream f = new ZipInputStream(File.OpenRead(file)); //读取压缩文件，并用此文件流新建 “ZipInputStream”对象
            ZipEntry zp = f.GetNextEntry();    //获取解压文件流中的项目。 另注（我的理解）：在压缩包里每个文件都以“ZipEntry”形式存在，其中包括存放文件的目录信息。如果空目录被压缩，该目录下将出现一个名称为空、大小为 0 、“Crc”属性为 00000000 的“文件”。此文件只是个标记，不会被解压。
            while (zp != null)
            {
                string un_tmp2;
                if (zp.Name.IndexOf("\\") >= 0) //获取文件的目录信息
                {
                    int tmp1 = zp.Name.LastIndexOf("");
                    un_tmp2 = zp.Name.Substring(0, tmp1);
                    Directory.CreateDirectory(destFolder + @"\" + un_tmp2); //必须先创建目录，否则解压失败 --- （A） 关系到下面的步骤（B）
                }
                if (!zp.IsDirectory && zp.Crc != 00000000L) //此“ZipEntry”不是“标记文件”
                {
                    int i = 2048;
                    byte[] b = new byte[i];  //每次缓冲 2048 字节
                    FileStream s = File.Create(destFolder + @"\" + zp.Name); //（B)-新建文件流
                    while (true) //持续读取字节，直到一个“ZipEntry”字节读完
                    {
                        i = f.Read(b, 0, b.Length); //读取“ZipEntry”中的字节
                        if (i > 0)
                        {
                            s.Write(b, 0, i); //将字节写入新建的文件流
                        }
                        else
                        {
                            break; //读取的字节为 0 ，跳出循环
                        }
                    }
                    s.Close();
                }
                zp = f.GetNextEntry();
            }
            f.Close();
            i2++;
        }

        /// <summary>
        /// 压缩文件
        /// </summary>
        /// <param name="fileList">文件列表</param>
        /// <param name="zipFile">压缩后的文件</param>
        public void ZipFile(List<string> fileList, string zipFile)
        {
                ZipOutputStream u = new ZipOutputStream(File.Create(zipFile));            //新建压缩文件流 “ZipOutputStream”
                foreach(string s in fileList)
                {
                    if (s != "")  //分离出来的文件名不为空
                    {
                        this.AddZipEntry(s, u, out u); //向压缩文件流加入内容
                    }
                }
                u.Finish(); // 结束压缩
                u.Close();
        }

        /// <summary>
        /// 增加一个压缩块
        /// </summary>
        /// <param name="s"></param>
        /// <param name="u"></param>
        /// <param name="j"></param>
        private void AddZipEntry(string s, ZipOutputStream u, out ZipOutputStream j)
        {
            if (File.Exists(s)) //文件的处理
            {
                u.SetLevel(9);      //压缩等级
                FileStream f = File.OpenRead(s);
                byte[] b = new byte[f.Length];
                f.Read(b, 0, b.Length);           //将文件流加入缓冲字节中
                ZipEntry z = new ZipEntry(this.ShortDir(s));
                u.PutNextEntry(z);              //为压缩文件流提供一个容器
                u.Write(b, 0, b.Length); //写入字节
                f.Close();
            }
            j = u;    //返回已添加数据的“ZipOutputStream”
        }

        private string ShortDir(string s)
        {
            //将文件的绝对路径转为相对路径
            string d = s.Substring(s.LastIndexOf(@"\")+1);
            return d;
        }
    }

    public class BZip2
    {
        /// <summary>
        /// BZip2 压缩文本
        /// </summary>
        /// <param name="uncompressedString">需要压缩的文本</param>
        /// <returns>压缩后的文本</returns>
        public static string Compress(string uncompressedString)
        {
            byte[] bytData = System.Text.Encoding.Unicode.GetBytes(uncompressedString);
            MemoryStream ms = new MemoryStream();
            Stream s = new ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream(ms);
            s.Write(bytData, 0, bytData.Length);
            s.Close();
            byte[] compressedData = (byte[])ms.ToArray();
            return System.Convert.ToBase64String(compressedData, 0, compressedData.Length);
        }
        
        /// <summary>
        /// BZip2 解压文本
        /// </summary>
        /// <param name="compressedString">需要解压的文本</param>
        /// <returns>解压后的文本</returns>
        public static string DeCompress(string compressedString)
        {
            System.Text.StringBuilder uncompressedString = new System.Text.StringBuilder();
            int totalLength = 0;
            byte[] bytInput = System.Convert.FromBase64String(compressedString); ;
            byte[] writeData = new byte[4096];
            Stream s2 = new ICSharpCode.SharpZipLib.BZip2.BZip2InputStream(new MemoryStream(bytInput));
            while (true)
            {
                int size = s2.Read(writeData, 0, writeData.Length);
                if (size > 0)
                {
                    totalLength += size;
                    uncompressedString.Append(System.Text.Encoding.Unicode.GetString(writeData, 0, size));
                }
                else
                {
                    break;
                }
            }
            s2.Close();
            return uncompressedString.ToString();
        } 
    }
}
